package com.cartoonrabbit.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cartoonrabbit.consts.ColockStatus;
import com.cartoonrabbit.consts.NotificationAPIURL;
import com.cartoonrabbit.consts.TradeStatus;
import com.cartoonrabbit.consts.WxAPIURL;
import com.cartoonrabbit.mapper.EarlyRecordMapper;
import com.cartoonrabbit.mapper.EarlyUserMapper;
import com.cartoonrabbit.mapper.UserMapper;
import com.cartoonrabbit.pojo.*;
import com.cartoonrabbit.mapper.EarlyActionMapper;
import com.cartoonrabbit.service.IEarlyActionService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cartoonrabbit.service.IRechargeOrderService;
import com.cartoonrabbit.service.IUserService;
import com.cartoonrabbit.service.IWxPayService;
import com.cartoonrabbit.vo.RespBean;
import com.cartoonrabbit.wxapp.properties.WxAppInfoProperties;
import com.cartoonrabbit.wxapp.properties.WxAppPayProperties;
import com.cartoonrabbit.wxapp.utils.PrimaryKeyUtils;
import com.cartoonrabbit.wxapp.utils.SignUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author LiuTeng
 * @since 2023-01-17
 */
@Service
public class EarlyActionServiceImpl extends ServiceImpl<EarlyActionMapper, EarlyAction> implements IEarlyActionService {

    @Autowired
    private EarlyActionMapper earlyActionMapper;

    @Autowired
    private EarlyRecordMapper earlyRecordMapper;
    @Autowired
    private EarlyUserMapper earlyUserMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private WxAppInfoProperties wxAppInfoProperties;

    @Autowired
    private WxAppPayProperties wxAppPayProperties;

    @Autowired
    private CloseableHttpClient closeableHttpClient;

    @Autowired
    private IRechargeOrderService rechargeOrderService;

    @Autowired
    private SignUtils signUtils;

    @Autowired
    private IWxPayService wxPayService;

    @Autowired
    private IUserService userService;

    @Override
    public RespBean getTwoActions(String openId) {

        /**
         * 第一个打卡活动记录：显示还未结算的打卡活动
         *返回内容： 活动id、活动总金额、活动总人数、前八人头像、活动状态、该用户购买状态、该用户打卡状态、创建时间
         * 第二个打卡活动记录：显示已结算的打卡活动
         *返回内容：活动id、活动金额、总人数、成功打卡人数、打卡失败人数、活动状态、早起之星、手气之星、毅力之星、活动创建时间
         */

        LocalDate nowDate = LocalDate.now();
        EarlyAction todayAction=earlyActionMapper.selectActionByTime(nowDate.toString());
        EarlyAction yesterdayAction=earlyActionMapper.selectActionByTime(nowDate.plusDays(-1).toString());
        Map<String,Object> resoult=new HashMap<>();
        if (ObjectUtils.isEmpty(todayAction)){
            // 没有说明在结算中
            resoult.put("todayAction",null);
        }else {
            Map<String,Object> todayActionMap=new HashMap<>();
            BeanUtil.copyProperties(todayAction,todayActionMap);
            // 0进行中
            // 1打卡已停止
            // 获取前八人头像
            List<String> eightImages=earlyRecordMapper.selectEightImages(todayAction.getActionId());
            todayActionMap.put("eightImages",eightImages);
            // 获取该用户购买状态
            EarlyRecord earlyRecord = earlyRecordMapper.selectOne(new QueryWrapper<EarlyRecord>().eq("user_id", openId).eq("action_id", todayAction.getActionId()));
            if (ObjectUtils.isEmpty(earlyRecord)){
                todayActionMap.put("payStatus",0);
                todayActionMap.put("colockStatus",0);
            }else {
                todayActionMap.put("payStatus",1);
                todayActionMap.put("colockStatus",earlyRecord.getColockStatus());
            }
            // 获取该用户打卡状态
            resoult.put("todayAction",todayActionMap);
        }

        if (ObjectUtils.isEmpty(yesterdayAction)){
            // 没有说明第一次活动
            resoult.put("yesterdayAction",null);
        }else {
            // 3打卡结算中
            // 4打卡已结算
            Map<String,Object> yesterdayActionMap=new HashMap<>();
            BeanUtil.copyProperties(yesterdayAction,yesterdayActionMap);
            List<String> eightImages=earlyRecordMapper.selectEightImages(yesterdayAction.getActionId());
            yesterdayActionMap.put("eightImages",eightImages);
            // 获取该用户购买状态
            EarlyRecord earlyRecord = earlyRecordMapper.selectOne(new QueryWrapper<EarlyRecord>().eq("user_id", openId).eq("action_id", yesterdayAction.getActionId()));
            if (ObjectUtils.isEmpty(earlyRecord)){
                yesterdayActionMap.put("payStatus",0);
                yesterdayActionMap.put("colockStatus",0);
            }else {
                yesterdayActionMap.put("payStatus",1);
                yesterdayActionMap.put("colockStatus",earlyRecord.getColockStatus());
            }
            // 早起之星、手气之星、毅力之星
            if (ObjectUtils.isEmpty(yesterdayAction.getEarlyStart())){
                yesterdayActionMap.put("earlyStart",null);
            }else {
                User earlyStart = userMapper.selectById(yesterdayAction.getEarlyStart());
                EarlyRecord earlyStartRecord = earlyRecordMapper.selectOne(new QueryWrapper<EarlyRecord>().eq("action_id",yesterdayAction.getActionId()).eq("user_id",yesterdayAction.getEarlyStart()));
                Map<String,Object> earlyStartMap=new HashMap<>();
                BeanUtil.copyProperties(earlyStartRecord,earlyStartMap);
                earlyStartMap.put("avatarUrl",earlyStart.getAvatarUrl());
                earlyStartMap.put("nickName",earlyStart.getNickName());
                yesterdayActionMap.put("earlyStart",earlyStartMap);
            }
            if (ObjectUtils.isEmpty(yesterdayAction.getLuckStart())){
                yesterdayActionMap.put("luckStart",null);
            }else {
                User luckStart = userMapper.selectById(yesterdayAction.getLuckStart());
                EarlyRecord luckStartRecord = earlyRecordMapper.selectOne(new QueryWrapper<EarlyRecord>().eq("action_id",yesterdayAction.getActionId()).eq("user_id",yesterdayAction.getLuckStart()));
                Map<String,Object> luckStartMap=new HashMap<>();
                BeanUtil.copyProperties(luckStartRecord,luckStartMap);
                luckStartMap.put("avatarUrl",luckStart.getAvatarUrl());
                luckStartMap.put("nickName",luckStart.getNickName());
                yesterdayActionMap.put("luckStart",luckStartMap);
            }

            if (ObjectUtils.isEmpty(yesterdayAction.getPowerStart())){
                yesterdayActionMap.put("powerStart",null);
            }else {
                User powerStart = userMapper.selectById(yesterdayAction.getPowerStart());
                EarlyUser powerearlyUser = earlyUserMapper.selectById(yesterdayAction.getPowerStart());
                Map<String,Object> powerStartMap=new HashMap<>();
                BeanUtil.copyProperties(powerearlyUser,powerStartMap);
                powerStartMap.put("avatarUrl",powerStart.getAvatarUrl());
                powerStartMap.put("nickName",powerStart.getNickName());
                yesterdayActionMap.put("powerStart",powerStartMap);
            }

            resoult.put("yesterdayAction",yesterdayActionMap);
        }

        return RespBean.success("SUCCESS",resoult);
    }

    @Override
    public RespBean doPrePay(Long money, String openId) throws Exception {
        // 生成订单
        RechargeOrder order = handleOrderInfo("卡通兔早起打卡报名",money, openId);
        if (order==null){
            return RespBean.fail("服务器异常，订单信息生成失败");
        }
        // 调用JSAPI接口获取预支付id
        HttpPost httpPost = new HttpPost(WxAPIURL.NATIVE);
        httpPost.addHeader("Accept", "application/json");
        httpPost.addHeader("Content-type","application/json; charset=utf-8");

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectMapper objectMapper = new ObjectMapper();
        ObjectNode rootNode = objectMapper.createObjectNode();
        rootNode.put("mchid",wxAppPayProperties.getMchId())
                .put("appid", wxAppInfoProperties.getAppId())
                .put("description", order.getDescription())
                .put("notify_url", NotificationAPIURL.ACCOUNT_RECHARGE)
                .put("out_trade_no", order.getOrderId())
                .put("time_expire",(order.getTimeExpire()
                        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss+08:00")))
                        .replace(" ","T"));// 过期时间
        // 支付金额
        rootNode.putObject("amount")
                .put("total", order.getTradeMoney().intValue());
        rootNode.putObject("payer")
                .put("openid", order.getOpenId());

        objectMapper.writeValue(bos, rootNode);

        httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
        CloseableHttpResponse response = closeableHttpClient.execute(httpPost);

        String bodyAsString = EntityUtils.toString(response.getEntity());
        // 获取预支付id
        JSONObject resObj = JSONUtil.parseObj(bodyAsString);
        String prepayId=null;
        if (resObj.getObj("code")!=null){
            return RespBean.fail("请求支付异常");
        }else {
            prepayId=resObj.getStr("prepay_id");
            // 获取成功后处理余额明细
            order.setPrepayId(prepayId);
            // 保存订单
            rechargeOrderService.save(order);
        }

        long times = System.currentTimeMillis() / 1000;
        String randomString = RandomUtil.randomString(32);
        String timeStamp=String.valueOf(times);
        String nonceStr=randomString;
        String pacKage="prepay_id="+prepayId;
        String signStr = signUtils.getSign(wxAppInfoProperties.getAppId(), times, randomString, pacKage);
        String paySign=signStr;
        //预支付id，时间戳，随机字符串，支付签名，签名类型
        Map<String,String> resultMap=new HashMap<>();
        resultMap.put("timeStamp",timeStamp);
        resultMap.put("nonceStr",nonceStr);
        resultMap.put("package",pacKage);
        resultMap.put("signType","RSA");
        resultMap.put("paySign",paySign);
        resultMap.put("orderId",order.getOrderId());
        return RespBean.success("SUCCESS",resultMap);
    }

    @Override
    @Transactional
    public RespBean doNotify(String orderId, Integer status, String openId) {
        if (status == 0) {
            // 删除订单
            removeById(orderId);
            return RespBean.success("SUCCESS", null);
        } else {
            // 查单
            //调用微信支付查单接口
            String orderStatusByString = null;
            try {
                orderStatusByString = wxPayService.queryOrderStatusByString(orderId);
            } catch (IOException e) {
                throw new RuntimeException("请求查单接口异常");
            }

            JSONObject entries = JSONUtil.parseObj(orderStatusByString);
            //获取微信支付端的状态
            Object tradeState = entries.getStr("trade_state");
            if (tradeState != null && tradeState.equals("SUCCESS")) {
                // 更新订单状态
                RechargeOrder order = rechargeOrderService.getById(orderId);
                order.setOrderId(orderId);
                order.setTradeStatus(TradeStatus.SUCCESS);
                order.setTradeId(entries.getStr("transaction_id"));
                order.setTradeContent(orderStatusByString);
                rechargeOrderService.updateById(order);
                //  更改用户制作次数
                User user = userService.getById(openId);
                User updateUser = new User();
                updateUser.setOpenId(openId);
                updateUser.setProductTimes(order.getProductTimes() + user.getProductTimes());
                user.setProductTimes(updateUser.getProductTimes());
                userService.updateById(updateUser);
                // 获取当天活动
                EarlyAction earlyAction = earlyActionMapper.selectActionByTime(LocalDate.now().toString());
                if (ObjectUtils.isEmpty(earlyAction)){
                    return RespBean.fail("活动不存在");
                }
                // todo 修改用户早起的投入收入等
                EarlyUser earlyUser = earlyUserMapper.selectById(openId);
                if (ObjectUtils.isEmpty(earlyUser)){
                    earlyUser=new EarlyUser();
                    // 创建打卡用户
                    earlyUser.setUserId(openId);
                    earlyUser.setTotalInput(0L);
                    earlyUserMapper.insert(earlyUser);
                }
                earlyUser.setTotalInput(order.getTradeMoney()+earlyUser.getTotalInput());
                earlyUserMapper.updateById(earlyUser);
                // todo 添加用户早起记录
                EarlyRecord earlyRecord = new EarlyRecord();
                earlyRecord.setActionId(earlyAction.getActionId());
                earlyRecord.setColockInput(order.getTradeMoney());
                earlyRecord.setColockIncome(0L);
                earlyRecord.setColockStatus(ColockStatus.NOCLOCK);
                earlyRecord.setUserId(openId);
                earlyRecordMapper.insert(earlyRecord);
                // todo 修改用户参与的活动的金额，人数
                earlyAction.setTotalMoney(earlyAction.getTotalMoney()+order.getTradeMoney());
                earlyAction.setTotalPerson(earlyAction.getTotalPerson()+1);
                updateById(earlyAction);
            }
            return RespBean.success("SUCCESS");
        }
    }

    @Override
    @Transactional
    public RespBean doClock(Integer actionId, String opennId) {
        // 判断当前打卡时间是否属于5:00-8:00
        EarlyAction earlyAction = earlyActionMapper.selectById(actionId);
        LocalDateTime actionCreateTime = earlyAction.getCreateTime();
        // 获取当前时间
        LocalDateTime nowDateTime = LocalDateTime.now();

        LocalDateTime localDateTime = actionCreateTime.plusDays(1);
        LocalDate localDate = localDateTime.toLocalDate();
        LocalDateTime fiveDateTime=LocalDateTime.parse(localDate.toString()+"T"+"05:00:00");
        LocalDateTime eightDateTime=LocalDateTime.parse(localDate.toString()+"T"+"08:00:00");
        if (nowDateTime.isBefore(fiveDateTime)||nowDateTime.isAfter(eightDateTime)){
            return RespBean.fail("请在规定时间内打卡");
        }
        // 获取用户记录
        EarlyRecord earlyRecord = earlyRecordMapper.selectOne(new QueryWrapper<EarlyRecord>().eq("action_id", actionId).eq("user_id", opennId));
        if (earlyRecord!=null){
            // 将用户的打卡状态设置成功
            earlyRecord.setColockStatus(ColockStatus.CLOCKED);
            earlyRecord.setColcokTime(nowDateTime);
            earlyRecordMapper.updateById(earlyRecord);
        }
        // 设置用户打卡成功天数
        EarlyUser earlyUser = earlyUserMapper.selectById(opennId);
        earlyUser.setSuccessDays(earlyUser.getSuccessDays()+1);
        // 修改持续天数
        // 判断昨天是否打卡
        LocalDate yesterday = LocalDate.now().plusDays(-1);
        EarlyRecord yesterDayEarlyRecord = earlyRecordMapper.selectOne(new QueryWrapper<EarlyRecord>()
                .eq("user_id", opennId).between("colcok_time",
                        yesterday.toString() + " " + "05:00:00",
                        yesterday.toString() + " " + "08:00:00"));
        if (yesterDayEarlyRecord==null){
           earlyUser.setCurrentColcok(0);
        }
        earlyUser.setCurrentColcok(earlyUser.getCurrentColcok()+1);
        if (earlyUser.getCurrentColcok()>earlyUser.getContinuColock()){
            earlyUser.setContinuColock(earlyUser.getCurrentColcok());
        }
        earlyUserMapper.updateById(earlyUser);
        return RespBean.success("SUCCESS");
    }

    private RechargeOrder handleOrderInfo(String description,Long money, String openId) {
        // 生成订单过期时间
        LocalDateTime time_expire = LocalDateTime.now().plusMinutes(10);
        RechargeOrder order = new RechargeOrder();
        order.setOrderId(PrimaryKeyUtils.getOrderNo());
        order.setOpenId(openId);
        order.setDescription(description);
        order.setTradeMoney(money);
        order.setTradeTime(LocalDateTime.now());
        order.setTradeStatus(TradeStatus.NOPAY);
        order.setTimeExpire(time_expire);
        order.setProductTimes(1);
        return order;
    }
}
